﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Minestorm.Retro.Entities
{
    public class NamedShortArray
    {
        public NamedShortArray()
        { }

        public NamedShortArray(string name, bool useForCollisions, params short[] array)
        {
            Array = array;
            Name = name;
        }

        public short[] Array;
        public string Name;
        public bool UseForCollisions;
    }

    public abstract class Entity
    {
        public Entity(GraphicsDevice graphics, Vector2 position)
        {
            _graphics = graphics;
            Position = position;
            ShouldDraw = true;
        }
        public BasicEffect BasicEffect { get; set; }
        public virtual Texture2D GetTexture() { return null; }

        public virtual bool DrawVertices { get { return true; } }

        public bool ShouldDraw { get; set; }
        public bool Hidden { get; set; }

        public TimeSpan BornOn { get; set; }

        public int Index { get; set; }

        private VertexBuffer _vertexBuffer;
        private IndexBuffer[] _indexBuffers;
        private GraphicsDevice _graphics;

        private List<short[]> _indiciesList;
        private VertexPositionColor[] _vertices;

        public Vector2 Position { get; set; }

        public abstract void Initialize();

        public List<short[]> IndiciesList { get { return _indiciesList; } }
        public VertexPositionColor[] Verticies { get { return _vertices; } }

        public int Points { get; protected set; }

        protected void SetVerticies<T>(T[] verticies)
            where T : struct
        {
            VertexDeclaration vd = null;

            if (verticies is VertexPositionColorTexture[])
            {
                vd = VertexPositionColorTexture.VertexDeclaration;
            }
            else if (verticies is VertexPositionTexture[])
            {
                vd = VertexPositionTexture.VertexDeclaration;
            }
            else if (verticies is VertexPositionColor[])
            {
                vd = VertexPositionColor.VertexDeclaration;
            }

            _vertexBuffer = new VertexBuffer(_graphics, vd, verticies.Length, BufferUsage.WriteOnly);
            
            _vertexBuffer.SetData(verticies);

            if (verticies is VertexPositionColor[])
                _vertices = verticies.Cast<VertexPositionColor>().ToArray();
        }

        protected void SetIndicies(string name, bool useForCollisions, params short[] indicies)
        {
            SetIndicies(new NamedShortArray()
            {
                Array = indicies,
                Name = name,
                UseForCollisions = useForCollisions
            });
        }

        protected void SetIndicies(params NamedShortArray[] indicies)
        {
            _indexBuffers = new IndexBuffer[indicies.Length];

            _indiciesList = new List<short[]>();

            for (var i = 0; i < indicies.Length; i++)
            {
                var array = indicies[i].Array;
                var name = indicies[i].Name;

                _indexBuffers[i] = new IndexBuffer(_graphics, IndexElementSize.SixteenBits, array.Length, BufferUsage.WriteOnly);
                _indexBuffers[i].Name = name;
                _indexBuffers[i].SetData(array);

                _indiciesList.Add(array);
            }
        }

        public virtual void Draw(GameTime gameTime)
        {
            DrawInternal(PrimitiveType.LineList, 0, 0, _vertexBuffer.VertexCount, 0, _graphics.Indices.IndexCount / 2);
        }

        protected void DrawInternal(PrimitiveType primitiveType, int baseVertex, int minVertexIndex, int numVertices, int startIndex, int primitiveCount)
        {
            _graphics.DrawIndexedPrimitives(primitiveType, baseVertex, minVertexIndex, numVertices, startIndex, primitiveCount);
        }

        public virtual void Update(GameTime gameTime)
        {
        }

        protected Vector2 WrapBounds(Vector2 position)
        {
            if (position.X < Constants.Level.MinX)
                return new Vector2(Constants.Level.MaxX, Position.Y);
            if (position.X > Constants.Level.MaxX)
                return new Vector2(Constants.Level.MinX, Position.Y);
            if (position.Y < Constants.Level.MinY)
                return new Vector2(Position.X, Constants.Level.MaxY);
            if (position.Y > Constants.Level.MaxY)
                return new Vector2(Position.X, Constants.Level.MinY);

            return position;
        }

        public VertexBuffer VertexBuffer { get { return _vertexBuffer; } }

        public IndexBuffer[] IndexBuffers { get { return _indexBuffers; } }

        public abstract Matrix GetWorld(string indexBufferName);
    }
}
